/*
 * Memory barriers
 *
 * (C) 2019.04.01 BuddyZhang1 <buddy.zhang@aliyun.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/init.h>
#include <linux/kernel.h>

/*
 * Memory barriers
 *
 *   Memory barrier is the general term applied to an instruction, or 
 *   sequence of instruction, that forces synchronization events by a
 *   processor with respect to retiring load/store instructions. The 
 *   ARM architecture defines a number of memory barriers that provide
 *   a range of functionality, include:
 *
 *   •    ordering of load/store instructions
 *   •    completion of load/store instructions
 *   •    context synchronization
 *
 *   ARMv7 require three explicit memory barriers to support the memory
 *   order model described in this chapter. In ARMv7 the memory barriers
 *   are provided as instructions that are available in the ARM and Thumb
 *   instruction sets, and in ARMv6 the memory barriers are performed by
 *   CP15 register writes. The three memory barriers are:
 *   
 *   •    Data Memory Barrier - DMB
 *   •    Data Synchronization Barrier - DSB
 *   •    Instruction Synchronization Barrier - ISB
 *
 *   ---Note---
 *   Depending on the required synchronization, a program might use memory
 *   barriers on their own, or it might use them in conjunction with cache
 *   and memory management maintenance operations that are only available
 *   when software exection is at PL1 or higher.
 *   ----------
 *
 *   The DMB and DSB memory barriers affect read and writes to the memory
 *   system generated by load/store instructions and data or unified cache
 *   maintenance operations being executed by the processor. Instruction
 *   fetches or accesses caused by a hardware translation table access are
 *   not explicit accesses.
 *
 * Shareability and access limitations on the data barrier operations
 *
 *   The DMS and DSB instruction can each take an optional limitation 
 *   argument that specifies:
 *
 *   •    the shareability domain over which the instruction must operate,
 *        as one of:
 *
 *        ----     full system
 *        ----     Outer Shareable
 *        ----     Inner Shareable
 *        ----     Non-shareable
 *
 *   •    the accesses for which the instruction operates, as one of:
 *
 *        ----     read and write accesses.
 *        ----     write accesses only.
 *
 *   By default, each instruction operates for read and write accesses, over
 *   the full system, and whether an implementation supports any other 
 *   options is IMPLEMENTATION DEFINED. See the information descriptors for
 *   more information about these arguments.
 *
 *   ---Note---
 *   ISB also supports an optional limitation argument, but supports only
 *   one value for that argument, that corresponds to full system operation.
 *   ----------
 *
 *   In an implementation that include the Virtualization Extensions, and
 *   supports shareability limitations on eht data barrier operations, the
 *   HCR.BSU field can upgrade the required shareability of the operation
 *   for an instruction that is executed in a Non-secure PL1 or PL0 mode.
 *
 *   Table HCR.BSU encoding
 *   --------+-----------------------------------------------------------
 *   HCR.BSU | Minimum shareability of instruction
 *   --------+-----------------------------------------------------------
 *   00      | No effect, shareability is as specified by the instruction
 *   --------+-----------------------------------------------------------
 *   01      | Inner Shareable
 *   --------+-----------------------------------------------------------
 *   10      | Outer Shareable
 *   --------+-----------------------------------------------------------
 *   11      | Full system
 *   --------+-----------------------------------------------------------
 *
 *   For an instruction executed in an Non-secure PL1 or PL0 mode, Table
 *   show HCR.BSU upgrades the shareability specified by the argument of
 *   DMB or DSB instruction.
 *
 *   Table Upgrading the shareability of data barrier operation
 *   -----------------------+-------------------+------------------------
 *   Shareability from DMB  | HCR.BSU           | Resultant Shareability
 *   or DSB argument        |                   |
 *   -----------------------+-------------------+------------------------
 *   Full system            | Any               | Full system
 *   -----------------------+-------------------+------------------------
 *   Outer Shareable        | 00, 01, or 10     | Outer Shareable
 *                          +-------------------+------------------------
 *                          | 11, Full system   | Full system
 *   -----------------------+-------------------+------------------------
 *   Inner Shareable        | 00 or 01          | Inner Shareable
 *                          +-------------------+------------------------
 *                          | 10, Outer Share   | Outer Shareable
 *                          +-------------------+------------------------
 *                          | 11, Full system   | Full system
 *   -----------------------+-------------------+------------------------
 *   Non-shareable          | 00, No effect     | Non-shareable
 *                          +-------------------+------------------------
 *                          | 01, Inner Share   | Inner Shareable
 *                          +-------------------+------------------------
 *                          | 10, Outer Share   | Outer Shareable
 *                          +-------------------+------------------------
 *                          | 11, Full system   | Full system
 *   -----------------------+-------------------+------------------------
 */

int debug_ISB(void)
{
	unsigned long SCTLR;
	unsigned long HCR;

	/* Detect SCTLR.CP15BEN */
	__asm__ volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR));
	if ((SCTLR >> 5) & 0x1) {
		printk("CP15 barrier operation enable!\n");
	} else {
		printk("CP15 barrier operation disabled. Their encoding are"
			" UNDEFINED.\n");
	}

#ifdef CONFIG_ARM_VIRT_EXT
	/* HCR: Hyp Configuration Register */
	__asm__ volatile ("mrc p15, 4, %0, c1, c1, 0" : "=r" (HCR));
	/* HCR.BSU,bits[11:10]
	 *   Barrier shareability upgrade. When this field is nonzero, it
	 *   upgrads the required shareability of DMB and DSB barrier
	 *   instructions executed in a Non-secure PL1 or PL0 mode, beyond
	 *   the effect specified in the instruction.
	 */
	switch ((HCR >> 10) & 0x3) {
	case 0x00:
		printk("No effect, shareability is as specified by the "
			"instruction.\n");
		break;
	case 0x01:
		printk("Inner Shareable.\n");
		break;
	case 0x02:
		printk("Outer Shareable.\n");
		break;
	case 0x03:
		printk("Full system.\n");
		break;
	}
#endif

	/* Data memory barrier */
	__asm__ volatile ("dmb");
	
	/* Data synchronization barrier */
	__asm__ volatile ("dsb");

	/* Instruction synchronization barrier */
	__asm__ volatile ("isb");

	return 0;
}
device_initcall(debug_ISB);
